﻿//  Copyright (c) 2011 Ray Liang (http://www.dotnetage.com)
//  Dual licensed under the MIT and GPL licenses:
//  http://www.opensource.org/licenses/mit-license.php
//  http://www.gnu.org/licenses/gpl.html

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Objects;
using System.Reflection;
using System.Linq.Expressions;
using System.Collections;
using System.Web;
using System.Web.Mvc;

namespace DNA.Mvc.jQuery
{
    public static class ModelBinder
    {
        public static ModelWrapper<TModel> Bind<TModel, TKey>(ObjectQuery<TModel> dataSource, Func<TModel, TKey> keySelector, QueryParams query)
        {
            int total = dataSource.Count();
            int skipCount = query.GetSkipRecordCount(true);
            List<TModel> data = null;

            if (!string.IsNullOrEmpty(query.OrderBy))
                data = dataSource.OrderBy(query.GenerateOrderByExpression()).Skip(skipCount).Take(query.Size).ToList();
            else
                data = dataSource.OrderBy(keySelector).Skip(skipCount).Take(query.Size).ToList();

            return new ModelWrapper<TModel>
            {
                Model = data.ToList(),
                Total = total
            };
        }

        public static ModelWrapper BindForGrid<TModel, TKey>(ObjectQuery<TModel> dataSource, Func<TModel, TKey> keySelector, QueryParams query)
        {
            int total = dataSource.Count();
            int skipCount = query.GetSkipRecordCount(true);
            IQueryable<TModel> queryBuilder = null;
            IEnumerable result = null;

            if (!string.IsNullOrEmpty(query.OrderBy))
            {
                if (!string.IsNullOrEmpty(query.Filter))
                {
                    queryBuilder = dataSource.Where(query.GetFilterExpression()).OrderBy(query.GenerateOrderByExpression()).Skip(skipCount).Take(query.Size);
                    total = dataSource.Where(query.GetFilterExpression()).Count();
                }
                else
                    queryBuilder = dataSource.OrderBy(query.GenerateOrderByExpression()).Skip(skipCount).Take(query.Size);
            }

            string[] groupFields = query.GetGroupByFields();

            if (groupFields != null)
            {
                if (string.IsNullOrEmpty(query.OrderBy))
                {
                    if (!string.IsNullOrEmpty(query.Filter))
                    {
                        queryBuilder = dataSource.Where(query.GetFilterExpression()).OrderBy("it." + groupFields[0]).Skip(skipCount).Take(query.Size).AsQueryable();
                        total = dataSource.Where(query.GetFilterExpression()).Count();
                    }
                    else
                        queryBuilder = dataSource.OrderBy("it." + groupFields[0]).Skip(skipCount).Take(query.Size).AsQueryable();
                }

                result = queryBuilder.GroupByMany(groupFields).ToList();
            }
            else
            {
                if (queryBuilder == null)
                {
                    if (!string.IsNullOrEmpty(query.Filter))
                    {
                        queryBuilder = dataSource.Where(query.GetFilterExpression()).OrderBy(keySelector).Skip(skipCount).Take(query.Size).AsQueryable();
                        total = dataSource.Where(query.GetFilterExpression()).Count();
                    }
                    else
                        queryBuilder = dataSource.OrderBy(keySelector).Skip(skipCount).Take(query.Size).AsQueryable();
                }

                result = queryBuilder.ToList();
            }

            return new ModelWrapper
            {
                Model = result,
                Total = total
            };
        }

        public static List<GroupingDataContainer> ConvertDataResult(IEnumerable<DynamicGroupResult> result)
        {
            var list = new List<GroupingDataContainer>();
            foreach (var g in result)
                list.Add(new GroupingDataContainer(g));
            return list;
        }
    }

    public class GroupingDataContainer
    {
        public object Key { get; set; }
        public bool HasSubgroups { get; set; }
        public int Count { get; set; }
        public int Level { get; set; }
        public IEnumerable Items { get; set; }

        public GroupingDataContainer(DynamicGroupResult groupResult) : this(groupResult, 0) { }

        public GroupingDataContainer(DynamicGroupResult groupResult, int level)
        {
            this.Key = groupResult.Key;
            this.Count = groupResult.Count;
            this.Level = level;
            if (groupResult.SubGroups != null)
            {
                this.HasSubgroups = true;
                var items = new List<GroupingDataContainer>();
                foreach (var group in groupResult.SubGroups)
                    items.Add(new GroupingDataContainer(group, this.Level + 1));
                Items = items;
            }
            else
            {
                this.HasSubgroups = false;
                Items = groupResult.Items;
            }
        }
    }
}
